package com.my.financial.domain;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.my.financial.controller.form.LoginForm;
import com.my.financial.controller.form.PageInfo;
import com.my.financial.controller.form.QueryForm;
import com.my.financial.controller.form.RegisteForm;
import com.my.financial.jpaRepository.AccountRepository;
import com.my.financial.jpaRepository.ItemRepository;
import com.my.financial.jpaRepository.UserRepository;

@Service
@Transactional
public class JpaService implements FinancialService {
	
	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private ItemRepository itemRepository;
	
	@Autowired
	private AccountRepository accountRepository;

	@Override
	public User login(LoginForm loginForm) {
		String name = loginForm.getUserName();
		String ps = loginForm.getPassword();
		return userRepository.findByUserNameAndPassword(name, ps);
	}

	@Override
	public void register(RegisteForm registeForm) {
		User user = formToUser(registeForm);
		user = userRepository.save(user);
		FinancialAccount account = new FinancialAccount();
		account.setAccountType("现金账户");
		account.setAccount("现金口袋");
		account.setBalance(new BigDecimal(0));
		account.setUser(user);
		accountRepository.save(account);
	}

	@Override
	public void addMember(String member, Long userId) {
		User user = userRepository.findOne(userId);
		user.setAllMembers(user.getAllMembers()+","+member);
		userRepository.saveAndFlush(user);
	}

	@Override
	public void deleteMember(String member, Long userId) {
		User user = userRepository.findOne(userId);
		String allMembers = user.getAllMembers().replace(","+member,"");
		user.setAllMembers(allMembers);
		userRepository.saveAndFlush(user);
	}

	@Override
	public List<String> findAllMembers(Long userId) {
		String[] arr =userRepository.findOne(userId).getAllMembers().split(",");
		return Arrays.asList(arr);
	}

	@Override
	public void saveUser(User user) {
		userRepository.save(user);
	}

	@Override
	public void deleteUserById(Long id) {
		userRepository.delete(id);
	}

	@Override
	public User findUserById(String userId) {
		return userRepository.findOne(Long.parseLong(userId));
	}

	@Override
	public void saveAccount(FinancialAccount account) {
		accountRepository.save(account);
	}

	@Override
	public void deleteAccountById(Long id) {
		accountRepository.delete(id);
	}

	@Override
	@Transactional
	public void saveItem(FinancialItem item) {
		FinancialAccount account = accountRepository.findOne(item.getAccount().getId());
		if (item.getType().equals("收入")) {
			account.setBalance(account.getBalance().add(item.getAmount()));
			item.setAccount(account);
		} else if (item.getType().equals("支出")) {
			account.setBalance(account.getBalance().subtract(item.getAmount()));
			item.setAccount(account);
		}
		itemRepository.save(item);
	}

	@Override
	public void batchDeleteItemById(String multiId) {
		for(String id:multiId.split(",")){
			itemRepository.delete(Long.parseLong(id));
		}
	}

	@Override
	public List<FinancialItem> findItemByQueryForm(QueryForm queryForm,
			PageInfo pageInfo) {
		final int CountPerPage = pageInfo.getCountPerPage();
		Pageable pageable = new PageRequest(pageInfo.getPageNum()-1,CountPerPage);
		Page<FinancialItem> page = itemRepository.findAll(getQueryItemSpec(queryForm),pageable);
		return page.getContent();
	}

	@Override
	public PageInfo findPageInfo(QueryForm queryForm, PageInfo pageInfo) {
		Long count = itemRepository.count(getQueryItemSpec(queryForm));
		pageInfo.setTotalRows(count.intValue());
		return pageInfo;
	}

	@Override
	public boolean checkUserName(String userName) {
		return userRepository.findByUserName(userName)==null?true:false;
	}

	@Override
	public List<FinancialAccount> findAllAccount(Long userId) {
		return accountRepository.findByUserId(userId);
	}

	@Override
	public QueryForm getStartAndEndTime(String dateType, String dateNum) {
		QueryForm queryForm = new QueryForm();
		Calendar cal = Calendar.getInstance();
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String startTime = null; 
		String endTime = null;
		
		if (StringUtils.isBlank(dateType)) {
			return null;
		} else if (dateType.equals("月")) {
	        cal.set(Calendar.DAY_OF_MONTH,1);
			if (StringUtils.isNoneBlank(dateNum)) {
				cal.add(Calendar.MONTH, Integer.parseInt(dateNum));
			}
			startTime = dateFormat.format(cal.getTime());
			cal.add(Calendar.MONTH,1);
			endTime = dateFormat.format(cal.getTime());
		} else if (dateType.equals("周")) {
			cal.add(Calendar.DATE, -1);
			cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			if (StringUtils.isNoneBlank(dateNum)) {
				cal.add(Calendar.DATE, 7 * (Integer.parseInt(dateNum)));
			}
			startTime = dateFormat.format(cal.getTime());
			cal.add(Calendar.DATE, 7);
			endTime = dateFormat.format(cal.getTime());
		} else if (dateType.equals("日")) {
			if (StringUtils.isNoneBlank(dateNum)) {
				cal.add(Calendar.DATE, Integer.parseInt(dateNum));
			}
			startTime = dateFormat.format(cal.getTime());
			cal.add(Calendar.DATE,1);
			endTime = dateFormat.format(cal.getTime());
		}
		queryForm.setStarttime(startTime);
		queryForm.setEndtime(endTime);
		return queryForm;
	}

	@Override
	public String getDateRange(QueryForm queryForm, String dateType) {
		final String startTime = queryForm.getStarttime();
		final String endTime = queryForm.getEndtime();
		String dateRange = null;
		if(dateType.equals("月")){
			String[] start = startTime.split("-");
			dateRange = start[0]+"年"+start[1]+"月份";
		}else if(dateType.equals("周")){
			dateRange = startTime+"至"+endTime;
		}else if(dateType.equals("日")){
			dateRange = startTime;
		}
		return dateRange;
	}

	private User formToUser(RegisteForm registeForm) {
		User user = new User();
		user.setUserName(registeForm.getUserName());
		user.setPassword(registeForm.getPassword());
		user.setEmail(registeForm.getEmail());
		user.setAllMembers("本人,家庭公用");
		return user;
	}
	
	private Date stringToDate(String time){
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			return sdf.parse(time);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	private Specification<FinancialItem> getQueryItemSpec(QueryForm queryForm) {
		final String type = queryForm.getType();
		final String item = queryForm.getItem();
		final String startTime = queryForm.getStarttime();
		final String endTime = queryForm.getEndtime();
		final String member = queryForm.getMember();
		final User user = queryForm.getUser();
		return new Specification<FinancialItem>() {
			@Override
			public Predicate toPredicate(Root<FinancialItem> root,
					CriteriaQuery<?> query, CriteriaBuilder builder) {
				List<Predicate> list = new ArrayList<Predicate>();
				if(StringUtils.isNoneBlank(type)&&!type.equals("全部")){  
					list.add(builder.equal(root.get("type"), type));
				}
				if(StringUtils.isNoneBlank(item)&&!item.equals("全部")){  
					list.add(builder.equal(root.get("item"), item));    
				}  
				if(StringUtils.isNoneBlank(member)&&!member.equals("全部")){  
					list.add(builder.equal(root.get("member").as(String.class), member));
				}
				if(StringUtils.isNoneBlank(startTime)){
					list.add(builder.greaterThanOrEqualTo(root.get("createTime").as(Date.class), stringToDate(startTime)));    
				}
				if(StringUtils.isNoneBlank(endTime)){
					list.add(builder.lessThanOrEqualTo(root.get("createTime").as(Date.class), stringToDate(endTime)));    
				}
				list.add(builder.equal(root.get("user").as(User.class), user));
				Predicate[] p = new Predicate[list.size()];
				return builder.and(list.toArray(p));
			}
		};
	}
}
